﻿#Region "Imports"
Imports System.DirectoryServices
#End Region

Public Class IIsService
    Implements IDisposable

#Region "Privates"

    Private _ServiceEntry As DirectoryEntry
    Private _ApplicationPoolsEntry As DirectoryEntry

#End Region

#Region "Properties"

    Public ReadOnly Property Sites() As IIsSite()
        Get

            Dim WebSites() As IIsSite = {}

            Try

                Dim SiteEntries = From wse As DirectoryEntry In _ServiceEntry.Children _
                                  Where wse.SchemaClassName = SiteSchemaClassName _
                                  Select wse

                For Each se In SiteEntries

                    ReDim Preserve WebSites(WebSites.Length)
                    WebSites(WebSites.Length - 1) = New IIsSite(se, New DirectoryEntry(se.Path & "/Root"))

                Next

            Catch ex As Exception

                GetPropertyEx("Sites", ex)

            End Try

            Return WebSites

        End Get
    End Property

    Public ReadOnly Property ApplicationPools() As IIsApplicationPool()
        Get

            Dim AppPools() As IIsApplicationPool = {}

            Try

                Dim AppPoolEntries = From ape As DirectoryEntry In _ApplicationPoolsEntry.Children _
                                     Where ape.SchemaClassName = ApplicationPoolSchemaClassName _
                                     Select ape

                For Each ae In AppPoolEntries

                    ReDim Preserve AppPools(AppPools.Length)
                    AppPools(AppPools.Length - 1) = New IIsApplicationPool(ae)

                Next

            Catch ex As Exception

                GetPropertyEx("ApplicationPools", ex)

            End Try

            Return AppPools

        End Get
    End Property

#End Region

#Region "Constructors and Destructors"

    Public Sub New()

        Dim ServiceName = FirstServiceName()
        Dim AppPoolsName = FirstAppPoolsName()

        If ServiceName = String.Empty Then

            Throw New Exception("No IIS Web Service Metabase entry found on this machine.")

        Else

            _ServiceEntry = New DirectoryEntry(IIsProviderPath & "/" & ServiceName)
            _ServiceEntry.RefreshCache()

        End If

        If AppPoolsName = String.Empty Then

            Throw New Exception("No Application Pools Metabase entry found on this machine.")

        Else

            _ApplicationPoolsEntry = New DirectoryEntry(IIsProviderPath & "/" & ServiceName & "/" & AppPoolsName)
            _ApplicationPoolsEntry.RefreshCache()

        End If

    End Sub

    Protected Overrides Sub Finalize()

        If Not _ApplicationPoolsEntry Is Nothing Then _ApplicationPoolsEntry.Close()
        If Not _ServiceEntry Is Nothing Then _ServiceEntry.Close()

    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose

        If Not _ApplicationPoolsEntry Is Nothing Then _ApplicationPoolsEntry.Close()
        If Not _ServiceEntry Is Nothing Then _ServiceEntry.Close()

    End Sub

#End Region

#Region "Private Functions and Methods"

    ''' <summary>
    ''' Gets the name of the first available WebServer Service. (mostly will be 'W3SVC')
    ''' </summary>
    ''' <returns>Name of the WebServer Service.</returns>
    ''' <remarks></remarks>
    Private Function FirstServiceName() As String

        Dim IIsEntry As DirectoryEntry = Nothing
        Dim ServiceName = ""

        Try

            IIsEntry = New DirectoryEntry(IIsProviderPath)

            ServiceName = (From de As DirectoryEntry In IIsEntry.Children _
                           Where de.SchemaClassName = ServiceSchemaClassName _
                           Select de.Name).FirstOrDefault

        Catch ex As Exception

        Finally

            If Not IIsEntry Is Nothing Then IIsEntry.Close()

        End Try

        Return ServiceName

    End Function

    ''' <summary>
    ''' Gets the name of the first available AppPools Entry. (mostly will be 'AppPools')
    ''' </summary>
    ''' <returns>Name of AppPools Entry.</returns>
    ''' <remarks></remarks>
    Private Function FirstAppPoolsName() As String

        Dim IIsEntry As DirectoryEntry = Nothing
        Dim AppPoolsName = ""

        Try

            IIsEntry = New DirectoryEntry(IIsProviderPath & "/" & FirstServiceName())

            AppPoolsName = (From de As DirectoryEntry In IIsEntry.Children _
                            Where de.SchemaClassName = ApplicationPoolsSchemaClassName _
                            Select de.Name).FirstOrDefault

        Catch ex As Exception

        Finally

            If Not IIsEntry Is Nothing Then IIsEntry.Close()

        End Try

        Return AppPoolsName

    End Function

#End Region

#Region "Public Functions and Methods"

    Public Function AddAppPool(ByVal Id As String) As IIsApplicationPool

        AddAppPool = Nothing

        Try

            Dim ae As DirectoryEntry = _ApplicationPoolsEntry.Invoke("Create", ApplicationPoolSchemaClassName, Id)

            ae.CommitChanges()

            AddAppPool = New IIsApplicationPool(ae)

            ae.Close()

        Catch ex As Exception

            Throw New Exception(String.Format("An error occured while trying to add Application Pool '{0}'.", Id), ex)

        End Try

    End Function

    Public Function RemoveAppPool(ByVal Id As String) As Boolean

        Try

            _ApplicationPoolsEntry.Invoke("Delete", ApplicationPoolSchemaClassName, Id)

            Return True

        Catch ex As Exception

            Return False

        End Try

    End Function

    Public Function AddSite(ByVal Description As String, ByVal Path As String, ByVal Bindings() As SiteBinding) As IIsSite

        Try

            Dim ObjectsA() As Object

            If Bindings.Length > 0 Then

                ReDim ObjectsA(Bindings.Length - 1)

                For wsbI = 0 To Bindings.Length - 1

                    ObjectsA(wsbI) = String.Format("{0}:{1}:{2}", Bindings(wsbI).IP, Bindings(wsbI).Port, Bindings(wsbI).HostHeader)

                Next

            Else

                ObjectsA = New Object() {}

            End If

            Dim SiteId As String = _ServiceEntry.Invoke("CreateNewSite", Description, ObjectsA, Path)

            Dim ws = New DirectoryEntry(_ServiceEntry.Path & "\" & SiteId)
            Dim wr = New DirectoryEntry(ws.Path & "\Root")

            Return New IIsSite(ws, wr)

        Catch ex As Exception

            Return Nothing

        End Try

    End Function

    Public Function AddSite(ByVal Description As String, ByVal Path As String, ByVal Binding As SiteBinding) As IIsSite

        Return AddSite(Description, Path, New SiteBinding() {Binding})

    End Function

    Public Function AddSite(ByVal Description As String, ByVal Path As String, ByVal BindingHostHeader As String, Optional ByVal BindingPort As Integer = 80, Optional ByVal BindingIP As String = "") As IIsSite

        Return AddSite(Description, Path, New SiteBinding With {.IP = BindingIP, .Port = BindingPort, .HostHeader = BindingHostHeader})

    End Function

    Public Function RemoveSite(ByVal Id As String) As Boolean

        Try

            _ServiceEntry.Invoke("Delete", SiteSchemaClassName, Id)

            Return True

        Catch ex As Exception

            Return False

        End Try

    End Function

#End Region

End Class
